#pragma once
#include "Common.hpp"
#include "InetAddr.hpp"
#include <pthread.h>

class NoCopy
{
public:
	NoCopy() {}

	NoCopy(const NoCopy &) = delete;

	NoCopy &operator=(const NoCopy &) = delete;
	~NoCopy() {}
};

const int default_value = -1;
const int backlog = 8;

class Tcpserver : public NoCopy
{
public:
	Tcpserver(uint16_t port) : _port(port), _ip("127.0.0.1"), _isrunning(false), _listenfd(default_value)
	{
	}

	void Init()
	{
		// 创建套接字
		_listenfd = socket(AF_INET, SOCK_STREAM, 0);
		if (_listenfd < 0)
		{
			LOG(LogLevel::FATAL) << "listensocket error";
			exit(SOCKET_ERR);
		}

		LOG(LogLevel::INFO) << "listensocket success";

		// 绑定地址
		InetAddr local(_port);
		int n = bind(_listenfd, local.GetAddrPtr(), local.AddrLen());
		if (n < 0)
		{
			LOG(LogLevel::FATAL) << "bind error";
			exit(BIND_ERR);
		}

		// 设置监听状态
		n = listen(_listenfd, backlog);
		if (n < 0)
		{
			LOG(LogLevel::FATAL) << "listen error";
			exit(LISTEN_ERR);
		}

		LOG(LogLevel::INFO) << "listen success";
	}

	class ThreadData{
		public:
			ThreadData(int sockfd, InetAddr addr) : _sockfd(sockfd), _addr(addr) {}
			~ThreadData(){}

		public:
			int _sockfd;
			InetAddr _addr;
	};

	static void Service(int sockfd, InetAddr peer)
	{
		char buffer[1024];
		while (true)
		{
			int n = read(sockfd, buffer, sizeof(buffer));
			if (n > 0)
			{
				buffer[n] = 0;
				LOG(LogLevel::INFO) << peer.StringAddr() << " say: " << buffer;
				std::string echo = "echo: " + std::string(buffer);
				write(sockfd, echo.c_str(), echo.size());
			}
			else if (n == 0)
			{
				LOG(LogLevel::ERROR) << peer.StringAddr() << " disconnect";
				close(sockfd);
				return;
			}
			else
			{
				LOG(LogLevel::ERROR) << "read error";
				close(sockfd);
				return;
			}
		}
	}

	static void* Excute(void* arg){
		pthread_detach(pthread_self());
		ThreadData* td = static_cast<ThreadData*>(arg);
		Service(td->_sockfd, td->_addr);

		close(td->_sockfd);
		delete td;

		return nullptr;
	}

	void Connect(int sockfd, sockaddr_in peer){
		InetAddr addr(peer);
		LOG(LogLevel::INFO) << "new connection from: " << addr.StringAddr();

		ThreadData* td = new ThreadData(sockfd, addr);
		pthread_t tid;
		pthread_create(&tid, nullptr, Excute, (void*)td);
	}

	void Run()
	{
		_isrunning = true;
		while (_isrunning)
		{
			// 接受连接
			struct sockaddr_in local;
			socklen_t len = sizeof(local);
			memset(&local, 0, sizeof(local));
			int sockfd = accept(_listenfd, CHAGNGE_PTR(local), &len);
			if (sockfd < 0)
			{
				LOG(LogLevel::WARNING) << "accept error";
				continue;
			}
			InetAddr peer(local);
			LOG(LogLevel::INFO) << "accept success, peer addr: " << peer.StringAddr();
			Connect(sockfd, local);
		}
		
		_isrunning = false;
	}

	~Tcpserver()
	{
	}

private:
	uint16_t _port;
	std::string _ip;
	bool _isrunning;

	// 监听套接字，负责接收和管理连接请求
	int _listenfd;
};
